//go:build js || wasm

package godom

import "syscall/js"

// DocumentWrapper
// https://developer.mozilla.org/ru/docs/Web/API/Document
type DocumentWrapper interface {
	NodeWrapper

	ActiveElement() ElementWrapper
	AdoptedStyleSheets() ElementWrapper
	BgColor() string
	Body() ElementWrapper
	CharacterSet() string
	ChildElementCount() int
	Children() HTMLCollectionWrapper
	CompatMode() string
	ContentType() string
	Cookie() string
	CurrentScript() ElementWrapper
	DefaultView() ElementWrapper
	DesignMode() string
	Dir() string
	Doctype() js.Value
	DocumentElement() ElementWrapper
	DocumentURI() string
	Embeds() HTMLCollectionWrapper
	FirstElementChild() ElementWrapper
	Fonts() HTMLCollectionWrapper
	Forms() HTMLCollectionWrapper
	FullscreenElement() ElementWrapper
	FullscreenEnabled() bool
	Head() ElementWrapper
	Hidden() bool
	Images() HTMLCollectionWrapper
	Implementation() string
	LastElementChild() ElementWrapper
	LastModified() string
	Links() HTMLCollectionWrapper
	Location() ElementWrapper
	PictureInPictureElement() ElementWrapper
	PictureInPictureEnabled() string
	Plugins() HTMLCollectionWrapper
	PointerLockElement() ElementWrapper
	ReadyState() string
	Referrer() string
	Scripts() HTMLCollectionWrapper
	ScrollingElement() ElementWrapper
	StyleSheets() ElementWrapper
	Timeline() ElementWrapper
	Title() string
	URL() string
	VisibilityState() string

	AdoptNode(node NodeWrapper) NodeWrapper
	Append(nodes ...NodeWrapper)
	CaretPositionFromPoint(x, y int) ElementWrapper
	Close()
	CreateAttribute(name string) AttrWrapper
	CreateAttributeNS(namespaceURI, qualifiedName string) AttrWrapper
	CreateCDATASection(data string) CDATASectionWrapper
	CreateComment(data string) CommentWrapper
	CreateElement(tagName string) ElementWrapper
	CreateElementNS(namespaceURI, qualifiedName string) ElementWrapper
	CreateEvent(eventType string) EventWrapper
	CreateExpression(xpathText, namespaceURLMapper string) XPathExpressionWrapper
	CreateNodeIterator(root NodeWrapper, whatToShow int) NodeIteratorWrapper
	CreateNSResolver(node NodeWrapper) js.Value
	CreateProcessingInstruction(target, data string)
	CreateRange() RangeWrapper
	CreateTextNode(data string) NodeWrapper
	CreateTreeWalker(root NodeWrapper, whatToShow int) TreeWalkerWrapper
	ElementFromPoint(x, y int) ElementWrapper
	ElementsFromPoint(x, y int) ElementWrapper
	Evaluate(xpathExpression string, contextNode NodeWrapper, namespaceResolver js.Func, resultType int, result XPathResultWrapper) XPathResultWrapper
	ExitFullscreen()
	ExitPictureInPicture()
	ExitPointerLock()
	GetAnimations() js.Value //todo: переделать на массив
	GetElementById(id string) ElementWrapper
	GetElementsByClassName(className string) HTMLCollectionWrapper
	GetElementsByName(name string) HTMLCollectionWrapper
	GetElementsByTagName(tagName string) HTMLCollectionWrapper
	GetElementsByTagNameNS(namespace string, name string) HTMLCollectionWrapper
	GetSelection() SelectorWrapper
	HasFocus() bool
	HasStorageAccess() bool
	HasUnpartitionedCookieAccess() bool
	ImportNode(externalNode NodeWrapper, deep bool) NodeWrapper
	Open() DocumentWrapper
	Prepend(params ...NodeWrapper)
	QuerySelector(selectors string) ElementWrapper
	QuerySelectorAll(selectors string) HTMLCollectionWrapper
	ReplaceChildren(params ...NodeWrapper)
	//RequestStorageAccess()
	Write(markup string)
	Writeln(line string)
}

type Document struct {
	Node
}

func GetDocument() *Document {
	return &Document{Node{jsValue: js.Global().Get("document")}}
}

func (d *Document) ActiveElement() ElementWrapper {
	return &Element{Node{d.jsValue.Get("activeElement")}}
}

func (d *Document) AdoptedStyleSheets() ElementWrapper {
	return &Element{Node{d.jsValue.Get("adoptedStyleSheets")}}
}

func (d *Document) Body() ElementWrapper {
	return &Element{Node{d.jsValue.Get("body")}}
}

func (d *Document) BgColor() string {
	return d.jsValue.Get("bgColor").String()
}

func (d *Document) CharacterSet() string {
	return d.jsValue.Get("characterSet").String()
}

func (d *Document) ChildElementCount() int {
	return d.jsValue.Get("childElementCount").Int()
}

func (d *Document) Children() HTMLCollectionWrapper {
	return &HTMLCollection{d.jsValue.Get("children")}
}

func (d *Document) CompatMode() string {
	return d.jsValue.Get("compatMode").String()
}

func (d *Document) ContentType() string {
	return d.jsValue.Get("contentType").String()
}

func (d *Document) Cookie() string {
	return d.jsValue.Get("cookie").String()
}

func (d *Document) CurrentScript() ElementWrapper {
	return &Element{Node{d.jsValue.Get("currentScript")}}
}

func (d *Document) DefaultView() ElementWrapper {
	//todo: Window переделать на новый тип
	return &Element{Node{d.jsValue.Get("defaultView")}}
}

func (d *Document) DesignMode() string {
	return d.jsValue.Get("designMode").String()
}

func (d *Document) Dir() string {
	return d.jsValue.Get("dir").String()
}

func (d *Document) Doctype() js.Value {
	return d.jsValue.Get("doctype")
}

func (d *Document) DocumentElement() ElementWrapper {
	return &Element{Node{d.jsValue.Get("documentElement")}}
}

func (d *Document) DocumentURI() string {
	return d.jsValue.Get("documentURI").String()
}

func (d *Document) Embeds() HTMLCollectionWrapper {
	return &HTMLCollection{d.jsValue.Get("embeds")}
}

func (d *Document) FirstElementChild() ElementWrapper {
	return &Element{Node{d.jsValue.Get("firstElementChild")}}
}

func (d *Document) Fonts() HTMLCollectionWrapper {
	//todo: FontsFaceSet переделать на новый тип
	return &HTMLCollection{d.jsValue.Get("fonts")}
}

func (d *Document) Forms() HTMLCollectionWrapper {
	return &HTMLCollection{d.jsValue.Get("forms")}
}

func (d *Document) FullscreenElement() ElementWrapper {
	return &Element{Node{d.jsValue.Get("fullscreenElement")}}
}

func (d *Document) FullscreenEnabled() bool {
	return d.jsValue.Get("fullscreenEnabled").Bool()
}

func (d *Document) Head() ElementWrapper {
	return &Element{Node{d.jsValue.Get("head")}}
}

func (d *Document) Hidden() bool {
	return d.jsValue.Get("hidden").Bool()
}

func (d *Document) Images() HTMLCollectionWrapper {
	return &HTMLCollection{d.jsValue.Get("images")}
}

func (d *Document) Implementation() string {
	return d.jsValue.Get("implementation").String()
}

func (d *Document) LastElementChild() ElementWrapper {
	return &Element{Node{d.jsValue.Get("lastElementChild")}}
}

func (d *Document) LastModified() string {
	return d.jsValue.Get("lastModified").String()
}

func (d *Document) Links() HTMLCollectionWrapper {
	return &HTMLCollection{d.jsValue.Get("links")}
}

func (d *Document) Location() ElementWrapper {
	//todo: Location переделать на новый тип
	return &Element{Node{d.jsValue.Get("location")}}
}

func (d *Document) PictureInPictureElement() ElementWrapper {
	return &Element{Node{d.jsValue.Get("pictureInPictureElement")}}
}

func (d *Document) PictureInPictureEnabled() string {
	//todo: вызывает ошибку при bool
	return d.jsValue.Get("pictureInPictureEnabled").String()
}

func (d *Document) Plugins() HTMLCollectionWrapper {
	return &HTMLCollection{d.jsValue.Get("plugins")}
}

func (d *Document) PointerLockElement() ElementWrapper {
	return &Element{Node{d.jsValue.Get("pointerLockElement")}}
}

func (d *Document) ReadyState() string {
	return d.jsValue.Get("readyState").String()
}

func (d *Document) Referrer() string {
	return d.jsValue.Get("referrer").String()
}

func (d *Document) Scripts() HTMLCollectionWrapper {
	return &HTMLCollection{d.jsValue.Get("scripts")}
}

func (d *Document) ScrollingElement() ElementWrapper {
	return &Element{Node{d.jsValue.Get("scrollingElement")}}
}

func (d *Document) StyleSheets() ElementWrapper {
	//todo: StyleSheets переделать на новый тип и понять как работает
	return &Element{Node{d.jsValue.Get("stylesheets")}}
}

func (d *Document) Timeline() ElementWrapper {
	//todo: DocumentTimeline переделать на новый тип
	return &Element{Node{d.jsValue.Get("timeline")}}
}

func (d *Document) Title() string {
	return d.jsValue.Get("title").String()
}

func (d *Document) URL() string {
	return d.jsValue.Get("URL").String()
}

func (d *Document) VisibilityState() string {
	return d.jsValue.Get("visibilityState").String()
}

//
// Document методы
//

func (d *Document) AdoptNode(node NodeWrapper) NodeWrapper {
	return &Node{d.jsValue.Call("adoptNode", node.JSValue())}
}

func (d *Document) Append(nodes ...NodeWrapper) {
	for _, node := range nodes {
		d.jsValue.Call("append", node.JSValue())
	}
}

func (d *Document) CaretPositionFromPoint(x, y int) ElementWrapper {
	return &Element{Node{d.jsValue.Call("caretPositionFromPoint", x, y)}}
}

func (d *Document) Close() {
	d.jsValue.Call("close")
}

func (d *Document) CreateAttribute(name string) AttrWrapper {
	return &Attr{Node{d.jsValue.Call("createAttribute", name)}}
}

func (d *Document) CreateAttributeNS(namespaceURI, qualifiedName string) AttrWrapper {
	return &Attr{Node{d.jsValue.Call("createAttribute", namespaceURI, qualifiedName)}}
}

func (d *Document) CreateCDATASection(data string) CDATASectionWrapper {
	return &CDATASection{Node{d.jsValue.Call("createCDATASection", data)}}
}

func (d *Document) CreateComment(data string) CommentWrapper {
	return &Comment{Node{d.jsValue.Call("createComment", data)}}
}

func (d *Document) CreateElement(tagName string) ElementWrapper {
	//todo: Добавить свойства создаваемого элемента
	return &Element{Node{d.jsValue.Call("createElement", tagName)}}
}

func (d *Document) CreateElementNS(namespaceURI, qualifiedName string) ElementWrapper {
	//todo: Добавить свойства создаваемого элемента
	return &Element{Node{d.jsValue.Call("createElement", namespaceURI, qualifiedName)}}
}

func (d *Document) CreateEvent(eventType string) EventWrapper {
	return &Event{d.jsValue.Call("createEvent", eventType)}
}

func (d *Document) CreateExpression(xpathText, namespaceURLMapper string) XPathExpressionWrapper {
	return &XPathExpression{d.jsValue.Call("createExpression", xpathText, namespaceURLMapper)}
}

func (d *Document) CreateNodeIterator(root NodeWrapper, whatToShow int) NodeIteratorWrapper {
	return &NodeIterator{d.jsValue.Call("createNodeIterator", root.JSValue(), whatToShow)}
}

func (d *Document) CreateNSResolver(node NodeWrapper) js.Value {
	return d.jsValue.Call("createNSResolver", node.JSValue())
}

func (d *Document) CreateProcessingInstruction(target, data string) {
	d.jsValue.Call("createProcessingInstruction", target, data)
}

func (d *Document) CreateRange() RangeWrapper {
	return &Range{d.jsValue.Call("createRange")}
}

func (d *Document) CreateTextNode(data string) NodeWrapper {
	return &Node{d.jsValue.Call("createTextNode", data)}
}

func (d *Document) CreateTreeWalker(root NodeWrapper, whatToShow int) TreeWalkerWrapper {
	return &TreeWalker{d.jsValue.Call("createTreeWalker", root.JSValue(), whatToShow)}
}

func (d *Document) ElementFromPoint(x, y int) ElementWrapper {
	return &Element{Node{d.jsValue.Call("elementFromPoint", x, y)}}
}

func (d *Document) ElementsFromPoint(x, y int) ElementWrapper {
	return &Element{Node{d.jsValue.Call("elementsFromPoint", x, y)}}
}

func (d *Document) Evaluate(xpathExpression string, contextNode NodeWrapper, namespaceResolver js.Func, resultType int, result XPathResultWrapper) XPathResultWrapper {
	return &XPathResult{d.jsValue.Call("evaluate", xpathExpression, contextNode.JSValue(), namespaceResolver, resultType, result.JSValue())}
}

func (d *Document) ExitFullscreen() {
	d.jsValue.Call("exitFullscreen")
}

func (d *Document) ExitPictureInPicture() {
	d.jsValue.Call("exitPictureInPicture")
}

func (d *Document) ExitPointerLock() {
	d.jsValue.Call("exitPointerLock")
}

func (d *Document) GetAnimations() js.Value {
	return d.jsValue.Call("getAnimations")
}

func (d *Document) GetElementById(id string) ElementWrapper {
	return &Element{Node{d.jsValue.Call("getElementById", id)}}
}

func (d *Document) GetElementsByClassName(className string) HTMLCollectionWrapper {
	return &HTMLCollection{d.jsValue.Call("getElementsByClassName", className)}
}

func (d *Document) GetElementsByName(name string) HTMLCollectionWrapper {
	return &HTMLCollection{d.jsValue.Call("getElementsByName", name)}
}

func (d *Document) GetElementsByTagName(tagName string) HTMLCollectionWrapper {
	return &HTMLCollection{d.jsValue.Call("getElementsByTagName", tagName)}
}

func (d *Document) GetElementsByTagNameNS(namespace string, name string) HTMLCollectionWrapper {
	return &HTMLCollection{d.jsValue.Call("getElementsByTagNameNS", namespace, name)}
}

func (d *Document) GetSelection() SelectorWrapper {
	return &Selector{d.jsValue.Call("getSelection")}
}

func (d *Document) HasFocus() bool {
	return d.jsValue.Call("hasFocus").Bool()
}

func (d *Document) HasStorageAccess() bool {
	return d.jsValue.Call("hasStorageAccess").Bool()
}

func (d *Document) HasUnpartitionedCookieAccess() bool {
	return d.jsValue.Call("hasUnpartitionedCookieAccess").Bool()
}

func (d *Document) ImportNode(externalNode NodeWrapper, deep bool) NodeWrapper {
	return &Node{d.jsValue.Call("importNode", externalNode.JSValue(), deep)}
}

func (d *Document) Open() DocumentWrapper {
	return &Document{Node{d.jsValue.Call("open")}}
}

func (d *Document) Prepend(params ...NodeWrapper) {
	for _, param := range params {
		d.jsValue.Call("prepend", param.JSValue())
	}
}

func (d *Document) QuerySelector(selectors string) ElementWrapper {
	return &Element{Node{d.jsValue.Call("querySelector", selectors)}}
}

func (d *Document) QuerySelectorAll(selectors string) HTMLCollectionWrapper {
	return &HTMLCollection{d.jsValue.Call("querySelectorAll", selectors)}
}

func (d *Document) ReplaceChildren(params ...NodeWrapper) {
	for _, param := range params {
		d.jsValue.Call("replaceChildren", param.JSValue())
	}
}

func (d *Document) Write(markup string) {
	d.jsValue.Call("write", markup)
}

func (d *Document) Writeln(line string) {
	d.jsValue.Call("writeln", line)
}
